/* Copyright (c) 2010, mitsuhisa.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the misuhisa.net nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>
#include <sstream>
#include <cstring>
#include "nyu.hpp"

#ifdef NYU_MM_DEBUG
#include "MemoryManager.hpp"
#endif

using namespace nyu;

namespace {

Value nyu_print(Context& c) {
	for (int i = 1, j = c.currentArgc(); i < j; i++) {
		Value v = c.currentArgv(i);

		switch (value_tag(v)) {
		case VALUE_TAG_INT:
			std::cout << value_to_int(v);
			break;

		case VALUE_TAG_OBJECT:
			if (is_null(v)) {
			    std::cout << "(null)";
			} else {
				Handle<String> s(value_to_object(v)->toString(c));
				std::cout << s->strval();
			}
			break;
		}
	}

	std::cout << std::flush;

	return NULL_VALUE;
}

Value nyu_println(Context& c) {
	nyu_print(c);

	std::cout << std::endl;

	return NULL_VALUE;
}

Value nyu_load(Context& c) {
	return NULL_VALUE;
}

}

int main(int argc, char** argv) {
	if (argc < 2) {
		std::cerr << "usage: " << argv[0] << " file.nyu" << std::endl;
		return 1;
	}

    int ret = 0;

	{
        Context c;

        c.putFunction("print", nyu_print);
        c.putFunction("println", nyu_println);
        c.putFunction("load", nyu_load);

        c.currentArgc(argc - 1);
        for (int i = 1; i < argc; i++) {
            c.currentArgv(i - 1, object_to_value(new DynamicString(argv[i])));
        }

        try {
            make_handle(c.evalFile(argv[1]));
        } catch (std::exception& e) {
            std::cerr << e.what() << std::endl;
            ret = -1;
        }
	}

#ifdef NYU_MM_DEBUG
	MemoryManager& mm = MemoryManager::getInstance();

    std::cout << std::endl;
    std::cout << "---" << std::endl;

    mm.majorGC();

    std::cout << "totalAllocated=" << mm.getTotalAllocated() << std::endl;
    std::cout << "allocatedChunks=" << mm.getAllocatedChunks() << std::endl;
    std::cout << "alivedObjects=" << mm.countAlivedObjects() << std::endl;
    std::cout << "minorGCCount=" << mm.getMinorGCCount() << std::endl;
    std::cout << "majorGCCount=" << mm.getMajorGCCount() << std::endl;
#endif

	return ret;
}
